package glemipsc.instructions;

import glemipsc.Address;
import glemipsc.Function;
import glemipsc.GLEMipsC;
import glemipsc.Type;
import glemipsc.implementations.Argument;

import java.io.Serializable;
import java.util.List;

public class Relation extends BaseInstruction implements Serializable, Instruction, Expression {
	private Expression op1, op2;
	private String op;
	private Address addr;
	
	public Relation(Expression op1, Expression op2, String op) {
		this.op1 = op1;
		this.op2 = op2;
		this.op = op;
	}
	
	public Expression getOperand(int index) {
		if (index == 0)
			return op1;
		else if (index == 1)
			return op2;
		return null;
	}
	
	public int getNumberOfOperands() {
		return 2;
	}

	public int getSize() {
		return 0;
	}

	public Type getType() {
		return Type.createFromName("int");
	}

	public int getImmediateValue() {
		boolean res = false;
		if (op.equals("=="))
			res = (op1.getImmediateValue() == op2.getImmediateValue());
		else if (op.equals("<="))
			res = (op1.getImmediateValue() <= op2.getImmediateValue());
		else if (op.equals(">="))
			res = (op1.getImmediateValue() >= op2.getImmediateValue());
		else if (op.equals("<"))
			res = (op1.getImmediateValue() < op2.getImmediateValue());
		else if (op.equals(">"))
			res = (op1.getImmediateValue() > op2.getImmediateValue());
		else if (op.equals("!="))
			res = (op1.getImmediateValue() != op2.getImmediateValue());
		return res ? 1 : 0;
	}

	public boolean isImmediate() {
		return op1.isImmediate() && op2.isImmediate();
	}

	public Address getStoreAddress() {
		return addr;
	}

	public int getStoredSize() {
		// TODO Auto-generated method stub
		return 0;
	}

	public boolean isStored() {
		return !isImmediate();
	}

	public void setStoreAddress(Address addr) {
		this.addr = addr;
	}

	public void computeInstruction(Argument result, List<glemipsc.implementations.Instruction> instructions, Function func) {
		glemipsc.implementations.Implementation impl = GLEMipsC.compiler.getEnvironment().implementation;
		instructions.add(impl.getMov(result, impl.getImmediate(0)));
		Argument res1, res2, tmp;
		res1 = impl.getFreeRegister();
		op1.computeInstruction(res1, instructions, func);
		res2 = impl.getFreeRegister();
		op2.computeInstruction(res2, instructions, func);
		tmp = impl.getFreeRegister();
		instructions.add(impl.getSub(tmp, res1, res2, true));
		if (op.equals("=="))
			instructions.add(impl.getJnz(tmp, impl.getImmediate(1)));
		else if (op.equals("<="))
			instructions.add(impl.getJgz(tmp, impl.getImmediate(1)));
		else if (op.equals(">="))
			instructions.add(impl.getJlz(tmp, impl.getImmediate(1)));
		else if (op.equals("<"))
			instructions.add(impl.getJgez(tmp, impl.getImmediate(1)));
		else if (op.equals(">"))
			instructions.add(impl.getJlez(tmp, impl.getImmediate(1)));
		else if (op.equals("!="))
			instructions.add(impl.getJz(tmp, impl.getImmediate(1)));
		instructions.add(impl.getMov(result, impl.getImmediate(1)));
		impl.freeRegister(tmp);
		impl.freeRegister(res2);
		impl.freeRegister(res1);
	}

}
